package com.kinoshita.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kinoshita.admin.api.domain.PermissionDO;
import com.kinoshita.admin.entity.SysRole;
import com.kinoshita.admin.entity.SysRolePermission;
import com.kinoshita.admin.mapper.SysRoleMapper;
import com.kinoshita.admin.mapper.SysRolePermissionMapper;
import com.kinoshita.admin.service.IPermissionService;
import com.kinoshita.admin.service.IRoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinoshita.admin.api.domain.RoleDO;
import com.kinoshita.admin.api.query.RoleQueryDO;
import com.kinoshita.common.bean.BeanUtilsExtends;
import com.kinoshita.common.exception.SystemException;
import com.kinoshita.common.logger.LoggerUtil;
import com.kinoshita.common.result.PageDO;
import com.kinoshita.common.result.ResultDO;
import com.kinoshita.common.status.Constant;
import com.kinoshita.common.status.OpCode;
import com.kinoshita.common.status.StatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author reagan
 * @since 2022-08-29
 */
@Service
public class RoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements IRoleService {

    private static Logger logger = LoggerFactory.getLogger(RoleServiceImpl.class);

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysRolePermissionMapper sysRolePermissionMapper;

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private LoggerUtil loggerUtil;

    @Override
    public ResultDO add(RoleDO domain) {
        SysRole entity = new SysRole();
        ResultDO resultDO = BeanUtilsExtends.copy(entity, domain);
        boolean res = false;
        if(!resultDO.isSuccess()) {
            throw new SystemException(resultDO.getStatusCode());
        }
        entity.setCreateDate(LocalDateTime.now());
        entity.setModifiDate(entity.getModifiDate());
        entity.setIsDelete(Constant.IS_NOT_DELETE);
        entity.setStatus(Constant.OK);
        entity.setCreator("");
        entity.setModifier(entity.getCreator());
        res = this.save(entity);
        loggerUtil.setInfo(this.getClass().getName() + " add", OpCode.OP_CREATE, domain.getCreator(), "");
        logger.info(loggerUtil.toString());
        if(!res) {
            throw new SystemException(StatusCode.ROLE_ADD_ERROR);
        }
        bindPermission(entity.getId(), domain.getPermissionIds());
        return resultDO;
    }

    public void bindPermission(Long roleId, List<Long> permissionIds) {
        //角色绑定权力
        permissionIds.stream().forEach(id->{
            SysRolePermission sysRolePermission = new SysRolePermission();
            sysRolePermission.setRoleId(roleId);
            sysRolePermission.setPermissionId(id);
            int row = sysRolePermissionMapper.insert(sysRolePermission);
            if(row < 0) {
                throw new SystemException(StatusCode.PERMISSION_BIND_ROLE_ERROR);
            }
        });
        loggerUtil.setInfo(this.getClass().getName() + " bindPermission", OpCode.OP_CREATE, "", "");
        logger.info(loggerUtil.toString());
    }

    public void unBindPermission(Long roleId) {
        int row = sysRolePermissionMapper.delete(Wrappers.<SysRolePermission>lambdaQuery().eq(SysRolePermission::getRoleId, roleId));
        if(row < 0) {
            throw new SystemException(StatusCode.PERMISSION_UNBIND_ROLE_ERROR);
        }
        loggerUtil.setInfo(this.getClass().getName() + " unBindPermission", OpCode.OP_CREATE, "", "");
        logger.info(loggerUtil.toString());
    }

    @Override
    public ResultDO edit(RoleDO domain) {
        SysRole entity = new SysRole();
        ResultDO resultDO = BeanUtilsExtends.copy(entity, domain);
        boolean res = false;
        if(!resultDO.isSuccess()) {
            throw new SystemException(resultDO.getStatusCode());
        }
        entity.setModifiDate(LocalDateTime.now());
        entity.setModifier("");
        res = this.updateById(entity);
        loggerUtil.setInfo(this.getClass().getName() + " edit", OpCode.OP_EDIT, domain.getCreator(), "");
        logger.info(loggerUtil.toString());
        if(!res) {
            throw new SystemException(StatusCode.ROLE_EDIT_ERROR);
        }
        unBindPermission(domain.getId());
        bindPermission(domain.getId(), domain.getPermissionIds());
        return resultDO;
    }

    @Override
    public ResultDO delete(Long id) {
        ResultDO resultDO = new ResultDO();
        SysRole entity = new SysRole();
        entity.setId(id);
        entity.setIsDelete(Constant.IS_DELETE);
        entity.setModifiDate(LocalDateTime.now());
        entity.setModifier("");
        boolean res = this.updateById(entity);
        loggerUtil.setInfo(this.getClass().getName() + " delete", OpCode.OP_EDIT, "", "");
        logger.info(loggerUtil.toString());
        if(!res) {
            throw new SystemException(StatusCode.ROLE_EDIT_ERROR);
        }
        unBindPermission(id);
        return resultDO;
    }

    @Override
    public ResultDO get(Long id) {
        ResultDO resultDO = new ResultDO();
        SysRole entity = this.getById(id);
        RoleDO domain = getDomain(entity);
        loggerUtil.setInfo(this.getClass().getName() + " get", OpCode.OP_GET, "", "");
        logger.info(loggerUtil.toString());
        if(ObjectUtils.isEmpty(domain)) {
            throw new SystemException(StatusCode.ROLE_GET_ERROR);
        }
        //返回角色对应的权限
        resultDO = permissionService.getByRoleId(id);
        domain.setPermissionList((List<PermissionDO>) resultDO.getModel(Constant.DATA_MODEL_KEY));
        resultDO.setModel(Constant.DATA_MODEL_KEY, domain);
        return resultDO;
    }

    @Override
    public ResultDO query(RoleQueryDO query) {
        SysRole entity = new SysRole();
        ResultDO resultDO = BeanUtilsExtends.copy(entity,query);
        if (!resultDO.isSuccess()) {
            throw new SystemException(resultDO.getStatusCode());
        }
        QueryWrapper<SysRole> wrapper = new QueryWrapper(entity);
        Page<SysRole> page = new Page<>(query.getCurrentPage(),query.getPageSize());
        IPage<SysRole> iPage = null;
        iPage = sysRoleMapper.selectPage(page, wrapper);
        List<RoleDO> doList = getDomainCollection(iPage.getRecords());
        PageDO<RoleDO> pageDO = new PageDO<>();
        pageDO.setCurrentPage(iPage.getCurrent());
        pageDO.setPageCount(iPage.getPages());
        pageDO.setPageSize(iPage.getSize());
        pageDO.setRowCount(iPage.getTotal());
        pageDO.setData(doList);
        loggerUtil.setInfo(this.getClass().getName() + " query", OpCode.OP_QUERY, "", "");
        logger.info(loggerUtil.toString());
        resultDO.setModel(Constant.DATA_MODEL_KEY, pageDO);
        return resultDO;
    }

    private RoleDO getDomain(SysRole entity) {
        RoleDO domain = new RoleDO();
        if(ObjectUtils.isEmpty(entity)) {
            return null;
        }
        domain = BeanUtilsExtends.copyProperties(domain, entity) ? domain : null;
        return domain;
    }

    private List<RoleDO> getDomainCollection(List<SysRole> list) {
        List<RoleDO> doList = new ArrayList<>();
        if(list.size() > 0) {
            for(SysRole entity : list) {
                RoleDO domain = this.getDomain(entity);
                if(domain == null) {
                    return Collections.emptyList();
                }
                doList.add(domain);
            }
        } else {
            return Collections.emptyList();
        }
        return doList;
    }
}
